﻿// Decompiled with JetBrains decompiler
// Type: System.Web.Razor.Parser.HtmlMarkupParser
// Assembly: System.Web.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
// MVID: 682513D6-F37E-48AC-9909-F3EE103CFF14
// Assembly location: D:\Project\Idea\无人机外网\uav\客户端工程\排查工具\bin\Release\System.Web.Razor.dll

using System.Collections.Generic;
using System.Linq;
using System.Web.Razor.Editor;
using System.Web.Razor.Generator;
using System.Web.Razor.Parser.SyntaxTree;
using System.Web.Razor.Resources;
using System.Web.Razor.Text;
using System.Web.Razor.Tokenizer;
using System.Web.Razor.Tokenizer.Symbols;

namespace System.Web.Razor.Parser
{
  /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code. Represents a parser specifically for parsing HTML markup.</summary>
  public class HtmlMarkupParser : TokenizerBackedParser<HtmlTokenizer, HtmlSymbol, HtmlSymbolType>
  {
    private SourceLocation _lastTagStart = SourceLocation.Zero;
    private HtmlSymbol _bufferedOpenAngle;
    private ISet<string> _voidElements = (ISet<string>) new HashSet<string>((IEqualityComparer<string>) StringComparer.OrdinalIgnoreCase)
    {
      "area",
      "base",
      "br",
      "col",
      "command",
      "embed",
      "hr",
      "img",
      "input",
      "keygen",
      "link",
      "meta",
      "param",
      "source",
      "track",
      "wbr"
    };

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code. Parses the next HTML block.</summary>
    public override void ParseBlock()
    {
      if (this.Context == null)
        throw new InvalidOperationException(RazorResources.Parser_Context_Not_Set);
      using (this.PushSpanConfig(new Action<SpanBuilder>(this.DefaultMarkupSpan)))
      {
        using (this.Context.StartBlock(BlockType.Markup))
        {
          if (!this.NextToken())
            return;
          this.AcceptWhile(HtmlMarkupParser.IsSpacingToken(true));
          if (this.CurrentSymbol.Type == HtmlSymbolType.OpenAngle)
            this.TagBlock(new Stack<Tuple<HtmlSymbol, SourceLocation>>());
          else if (this.CurrentSymbol.Type == HtmlSymbolType.Transition)
          {
            this.Output(SpanKind.Markup);
            this.AcceptAndMoveNext();
            this.Span.EditHandler.AcceptedCharacters = AcceptedCharacters.None;
            this.Span.CodeGenerator = SpanCodeGenerator.Null;
            this.Output(SpanKind.Transition);
            if (this.At(HtmlSymbolType.Transition))
            {
              this.Span.CodeGenerator = SpanCodeGenerator.Null;
              this.AcceptAndMoveNext();
              this.Output(SpanKind.MetaCode);
            }
            this.AfterTransition();
          }
          else
            this.Context.OnError(this.CurrentSymbol.Start, RazorResources.ParseError_MarkupBlock_Must_Start_With_Tag);
          this.Output(SpanKind.Markup);
        }
      }
    }

    private void DefaultMarkupSpan(SpanBuilder span)
    {
      span.CodeGenerator = (ISpanCodeGenerator) new MarkupCodeGenerator();
      span.EditHandler = new SpanEditHandler(new Func<string, IEnumerable<ISymbol>>(this.Language.TokenizeString), AcceptedCharacters.Any);
    }

    private void AfterTransition()
    {
      if (this.CurrentSymbol.Type == HtmlSymbolType.Text && this.CurrentSymbol.Content.Length > 0 && this.CurrentSymbol.Content[0] == ':')
      {
        Tuple<HtmlSymbol, HtmlSymbol> tuple = this.Language.SplitSymbol(this.CurrentSymbol, 1, HtmlSymbolType.Colon);
        this.Accept(tuple.Item1);
        this.Span.CodeGenerator = SpanCodeGenerator.Null;
        this.Output(SpanKind.MetaCode);
        if (tuple.Item2 != null)
          this.Accept(tuple.Item2);
        this.NextToken();
        this.SingleLineMarkup();
      }
      else
      {
        if (this.CurrentSymbol.Type != HtmlSymbolType.OpenAngle)
          return;
        this.TagBlock(new Stack<Tuple<HtmlSymbol, SourceLocation>>());
      }
    }

    private void SingleLineMarkup()
    {
      bool significantToAncestorBlock = this.Context.WhiteSpaceIsSignificantToAncestorBlock;
      this.Context.WhiteSpaceIsSignificantToAncestorBlock = true;
      this.Span.EditHandler = (SpanEditHandler) new SingleLineMarkupEditHandler(new Func<string, IEnumerable<ISymbol>>(this.Language.TokenizeString));
      this.SkipToAndParseCode(HtmlSymbolType.NewLine);
      if (!this.EndOfFile && this.CurrentSymbol.Type == HtmlSymbolType.NewLine)
      {
        this.AcceptAndMoveNext();
        this.Span.EditHandler.AcceptedCharacters = AcceptedCharacters.None;
      }
      this.PutCurrentBack();
      this.Context.WhiteSpaceIsSignificantToAncestorBlock = significantToAncestorBlock;
      this.Output(SpanKind.Markup);
    }

    private void TagBlock(Stack<Tuple<HtmlSymbol, SourceLocation>> tags)
    {
      bool complete = false;
      do
      {
        this.SkipToAndParseCode(HtmlSymbolType.OpenAngle);
        if (this.EndOfFile)
        {
          this.EndTagBlock(tags, true);
        }
        else
        {
          this._bufferedOpenAngle = (HtmlSymbol) null;
          this._lastTagStart = this.CurrentLocation;
          this._bufferedOpenAngle = this.CurrentSymbol;
          SourceLocation currentLocation = this.CurrentLocation;
          if (!this.NextToken())
          {
            this.Accept(this._bufferedOpenAngle);
            this.EndTagBlock(tags, false);
          }
          else
            complete = this.AfterTagStart(currentLocation, tags);
        }
      }
      while (tags.Count > 0);
      this.EndTagBlock(tags, complete);
    }

    private bool AfterTagStart(
      SourceLocation tagStart,
      Stack<Tuple<HtmlSymbol, SourceLocation>> tags)
    {
      if (!this.EndOfFile)
      {
        switch (this.CurrentSymbol.Type)
        {
          case HtmlSymbolType.Bang:
            this.Accept(this._bufferedOpenAngle);
            return this.BangTag();
          case HtmlSymbolType.Solidus:
            return this.EndTag(tagStart, tags);
          case HtmlSymbolType.QuestionMark:
            this.Accept(this._bufferedOpenAngle);
            return this.XmlPI();
          default:
            return this.StartTag(tags);
        }
      }
      else
      {
        if (tags.Count == 0)
          this.Context.OnError(this.CurrentLocation, RazorResources.ParseError_OuterTagMissingName);
        return false;
      }
    }

    private bool XmlPI()
    {
      this.AcceptAndMoveNext();
      return this.AcceptUntilAll(HtmlSymbolType.QuestionMark, HtmlSymbolType.CloseAngle);
    }

    private bool BangTag()
    {
      if (this.AcceptAndMoveNext())
      {
        if (this.CurrentSymbol.Type == HtmlSymbolType.DoubleHyphen)
        {
          this.AcceptAndMoveNext();
          return this.AcceptUntilAll(HtmlSymbolType.DoubleHyphen, HtmlSymbolType.CloseAngle);
        }
        if (this.CurrentSymbol.Type == HtmlSymbolType.LeftBracket)
        {
          if (this.AcceptAndMoveNext())
            return this.CData();
        }
        else
        {
          this.AcceptAndMoveNext();
          return this.AcceptUntilAll(HtmlSymbolType.CloseAngle);
        }
      }
      return false;
    }

    private bool CData()
    {
      if (this.CurrentSymbol.Type != HtmlSymbolType.Text || !string.Equals(this.CurrentSymbol.Content, "cdata", StringComparison.OrdinalIgnoreCase) || (!this.AcceptAndMoveNext() || this.CurrentSymbol.Type != HtmlSymbolType.LeftBracket))
        return false;
      return this.AcceptUntilAll(HtmlSymbolType.RightBracket, HtmlSymbolType.RightBracket, HtmlSymbolType.CloseAngle);
    }

    private bool EndTag(SourceLocation tagStart, Stack<Tuple<HtmlSymbol, SourceLocation>> tags)
    {
      HtmlSymbol currentSymbol = this.CurrentSymbol;
      if (!this.NextToken())
      {
        this.Accept(this._bufferedOpenAngle);
        this.Accept(currentSymbol);
        return false;
      }
      string str = string.Empty;
      if (this.At(HtmlSymbolType.Text))
        str = this.CurrentSymbol.Content;
      bool flag = this.RemoveTag(tags, str, tagStart);
      if (((tags.Count != 0 ? 0 : (string.Equals(str, SyntaxConstants.TextTagName, StringComparison.OrdinalIgnoreCase) ? 1 : 0)) & (flag ? 1 : 0)) != 0)
      {
        this.Output(SpanKind.Markup);
        return this.EndTextTag(currentSymbol);
      }
      this.Accept(this._bufferedOpenAngle);
      this.Accept(currentSymbol);
      this.AcceptUntil(HtmlSymbolType.CloseAngle);
      return this.Optional(HtmlSymbolType.CloseAngle);
    }

    private bool EndTextTag(HtmlSymbol solidus)
    {
      SourceLocation start = this._bufferedOpenAngle.Start;
      this.Accept(this._bufferedOpenAngle);
      this.Accept(solidus);
      this.AcceptAndMoveNext();
      int num = this.Optional(HtmlSymbolType.CloseAngle) ? 1 : 0;
      if (num == 0)
        this.Context.OnError(start, RazorResources.ParseError_TextTagCannotContainAttributes);
      else
        this.Span.EditHandler.AcceptedCharacters = AcceptedCharacters.None;
      this.Span.CodeGenerator = SpanCodeGenerator.Null;
      this.Output(SpanKind.Transition);
      return num != 0;
    }

    private bool IsTagRecoveryStopPoint(HtmlSymbol sym) => sym.Type == HtmlSymbolType.CloseAngle || sym.Type == HtmlSymbolType.Solidus || (sym.Type == HtmlSymbolType.OpenAngle || sym.Type == HtmlSymbolType.SingleQuote) || sym.Type == HtmlSymbolType.DoubleQuote;

    private void TagContent()
    {
      if (!this.At(HtmlSymbolType.WhiteSpace))
      {
        this.RecoverToEndOfTag();
      }
      else
      {
        while (!this.EndOfFile && !this.IsEndOfTag())
          this.BeforeAttribute();
      }
    }

    private bool IsEndOfTag()
    {
      if (this.At(HtmlSymbolType.Solidus))
      {
        if (this.NextIs(HtmlSymbolType.CloseAngle))
          return true;
        this.AcceptAndMoveNext();
      }
      return this.At(HtmlSymbolType.CloseAngle) || this.At(HtmlSymbolType.OpenAngle);
    }

    private void BeforeAttribute()
    {
      IEnumerable<HtmlSymbol> htmlSymbols1 = this.ReadWhile((Func<HtmlSymbol, bool>) (sym => sym.Type == HtmlSymbolType.WhiteSpace || sym.Type == HtmlSymbolType.NewLine));
      if (this.At(HtmlSymbolType.Transition))
      {
        this.Accept(htmlSymbols1);
        this.RecoverToEndOfTag();
      }
      else
      {
        Enumerable.Empty<HtmlSymbol>();
        if (this.At(HtmlSymbolType.Text))
        {
          IEnumerable<HtmlSymbol> htmlSymbols2 = this.ReadWhile((Func<HtmlSymbol, bool>) (sym =>
          {
            if (sym.Type == HtmlSymbolType.WhiteSpace || sym.Type == HtmlSymbolType.NewLine || (sym.Type == HtmlSymbolType.Equals || sym.Type == HtmlSymbolType.CloseAngle) || sym.Type == HtmlSymbolType.OpenAngle)
              return false;
            return sym.Type != HtmlSymbolType.Solidus || !this.NextIs(HtmlSymbolType.CloseAngle);
          }));
          if (!this.At(HtmlSymbolType.Equals))
          {
            this.Accept(htmlSymbols1);
            this.Accept(htmlSymbols2);
          }
          else
          {
            this.Output(SpanKind.Markup);
            using (this.Context.StartBlock(BlockType.Markup))
              this.AttributePrefix(htmlSymbols1, htmlSymbols2);
          }
        }
        else
        {
          this.Accept(htmlSymbols1);
          this.RecoverToEndOfTag();
        }
      }
    }

    private void AttributePrefix(
      IEnumerable<HtmlSymbol> whitespace,
      IEnumerable<HtmlSymbol> nameSymbols)
    {
      LocationTagged<string> content1 = ((IEnumerable<ISymbol>) nameSymbols).GetContent(this.Span.Start);
      int num = !content1.Value.StartsWith("data-", StringComparison.OrdinalIgnoreCase) ? 1 : 0;
      this.Accept(whitespace);
      this.Accept(nameSymbols);
      this.AcceptAndMoveNext();
      HtmlSymbolType quote = HtmlSymbolType.Unknown;
      if (this.At(HtmlSymbolType.SingleQuote) || this.At(HtmlSymbolType.DoubleQuote))
      {
        quote = this.CurrentSymbol.Type;
        this.AcceptAndMoveNext();
      }
      LocationTagged<string> content2 = this.Span.GetContent();
      if (num != 0)
      {
        this.Span.CodeGenerator = SpanCodeGenerator.Null;
        this.Output(SpanKind.Markup);
        while (!this.EndOfFile && !this.IsEndOfAttributeValue(quote, this.CurrentSymbol))
          this.AttributeValue(quote);
        LocationTagged<string> suffix = new LocationTagged<string>(string.Empty, this.CurrentLocation);
        if (quote != HtmlSymbolType.Unknown && this.At(quote))
        {
          suffix = this.CurrentSymbol.GetContent();
          this.AcceptAndMoveNext();
        }
        if (this.Span.Symbols.Count > 0)
        {
          this.Span.CodeGenerator = SpanCodeGenerator.Null;
          this.Output(SpanKind.Markup);
        }
        this.Context.CurrentBlock.CodeGenerator = (IBlockCodeGenerator) new AttributeBlockCodeGenerator((string) content1, content2, suffix);
      }
      else
      {
        this.SkipToAndParseCode((Func<HtmlSymbol, bool>) (sym => this.IsEndOfAttributeValue(quote, sym)));
        if (quote != HtmlSymbolType.Unknown)
          this.Optional(quote);
        this.Output(SpanKind.Markup);
      }
    }

    private void AttributeValue(HtmlSymbolType quote)
    {
      SourceLocation currentLocation1 = this.CurrentLocation;
      IEnumerable<HtmlSymbol> symbols1 = this.ReadWhile((Func<HtmlSymbol, bool>) (sym => sym.Type == HtmlSymbolType.WhiteSpace || sym.Type == HtmlSymbolType.NewLine));
      this.Accept(symbols1);
      if (this.At(HtmlSymbolType.Transition))
      {
        SourceLocation currentLocation2 = this.CurrentLocation;
        this.PutCurrentBack();
        this.Span.CodeGenerator = SpanCodeGenerator.Null;
        using (this.Context.StartBlock(BlockType.Markup))
        {
          this.Context.CurrentBlock.CodeGenerator = (IBlockCodeGenerator) new DynamicAttributeBlockCodeGenerator(((IEnumerable<ISymbol>) symbols1).GetContent(currentLocation1), currentLocation2);
          this.OtherParserBlock();
        }
      }
      else if (this.At(HtmlSymbolType.Text) && this.CurrentSymbol.Content.Length > 0 && (this.CurrentSymbol.Content[0] == '~' && this.NextIs(HtmlSymbolType.Solidus)))
      {
        SourceLocation currentLocation2 = this.CurrentLocation;
        this.VirtualPath();
        this.Span.CodeGenerator = (ISpanCodeGenerator) new LiteralAttributeCodeGenerator(((IEnumerable<ISymbol>) symbols1).GetContent(currentLocation1), new LocationTagged<SpanCodeGenerator>((SpanCodeGenerator) new ResolveUrlCodeGenerator(), currentLocation2));
      }
      else
      {
        IEnumerable<HtmlSymbol> symbols2 = this.ReadWhile((Func<HtmlSymbol, bool>) (sym => sym.Type != HtmlSymbolType.WhiteSpace && sym.Type != HtmlSymbolType.NewLine && sym.Type != HtmlSymbolType.Transition && !this.IsEndOfAttributeValue(quote, sym)));
        this.Accept(symbols2);
        this.Span.CodeGenerator = (ISpanCodeGenerator) new LiteralAttributeCodeGenerator(((IEnumerable<ISymbol>) symbols1).GetContent(currentLocation1), ((IEnumerable<ISymbol>) symbols2).GetContent(currentLocation1));
      }
      this.Output(SpanKind.Markup);
    }

    private bool IsEndOfAttributeValue(HtmlSymbolType quote, HtmlSymbol sym)
    {
      if (this.EndOfFile || sym == null)
        return true;
      return quote == HtmlSymbolType.Unknown ? this.IsUnquotedEndOfAttributeValue(sym) : sym.Type == quote;
    }

    private bool IsUnquotedEndOfAttributeValue(HtmlSymbol sym) => sym.Type == HtmlSymbolType.DoubleQuote || sym.Type == HtmlSymbolType.SingleQuote || (sym.Type == HtmlSymbolType.OpenAngle || sym.Type == HtmlSymbolType.Equals) || (sym.Type == HtmlSymbolType.Solidus && this.NextIs(HtmlSymbolType.CloseAngle) || (sym.Type == HtmlSymbolType.CloseAngle || sym.Type == HtmlSymbolType.WhiteSpace)) || sym.Type == HtmlSymbolType.NewLine;

    private void VirtualPath()
    {
      this.AcceptUntil(HtmlSymbolType.Transition, HtmlSymbolType.WhiteSpace, HtmlSymbolType.NewLine, HtmlSymbolType.SingleQuote, HtmlSymbolType.DoubleQuote);
      this.Span.EditHandler.EditorHints = EditorHints.VirtualPath;
    }

    private void RecoverToEndOfTag()
    {
      while (!this.EndOfFile)
      {
        this.SkipToAndParseCode(new Func<HtmlSymbol, bool>(this.IsTagRecoveryStopPoint));
        if (!this.EndOfFile)
        {
          this.EnsureCurrent();
          switch (this.CurrentSymbol.Type)
          {
            case HtmlSymbolType.OpenAngle:
              return;
            case HtmlSymbolType.Solidus:
              return;
            case HtmlSymbolType.CloseAngle:
              return;
            case HtmlSymbolType.DoubleQuote:
            case HtmlSymbolType.SingleQuote:
              this.ParseQuoted();
              continue;
            default:
              this.AcceptAndMoveNext();
              continue;
          }
        }
      }
    }

    private void ParseQuoted()
    {
      HtmlSymbolType type = this.CurrentSymbol.Type;
      this.AcceptAndMoveNext();
      this.ParseQuoted(type);
    }

    private void ParseQuoted(HtmlSymbolType type)
    {
      this.SkipToAndParseCode(type);
      if (this.EndOfFile)
        return;
      this.AcceptAndMoveNext();
    }

    private bool StartTag(Stack<Tuple<HtmlSymbol, SourceLocation>> tags)
    {
      Tuple<HtmlSymbol, SourceLocation> tag = Tuple.Create<HtmlSymbol, SourceLocation>(!this.At(HtmlSymbolType.Text) ? new HtmlSymbol(this.CurrentLocation, string.Empty, HtmlSymbolType.Unknown) : this.CurrentSymbol, this._lastTagStart);
      if (tags.Count == 0 && string.Equals(tag.Item1.Content, SyntaxConstants.TextTagName, StringComparison.OrdinalIgnoreCase))
      {
        this.Output(SpanKind.Markup);
        this.Span.CodeGenerator = SpanCodeGenerator.Null;
        this.Accept(this._bufferedOpenAngle);
        this.AcceptAndMoveNext();
        int absoluteIndex = this.CurrentLocation.AbsoluteIndex;
        IEnumerable<HtmlSymbol> symbols = this.ReadWhile(HtmlMarkupParser.IsSpacingToken(true));
        int num = this.At(HtmlSymbolType.Solidus) ? 1 : 0;
        if (num != 0)
        {
          this.Accept(symbols);
          this.AcceptAndMoveNext();
          absoluteIndex = this.CurrentLocation.AbsoluteIndex;
          symbols = this.ReadWhile(HtmlMarkupParser.IsSpacingToken(true));
        }
        if (!this.Optional(HtmlSymbolType.CloseAngle))
        {
          this.Context.Source.Position = absoluteIndex;
          this.NextToken();
          this.Context.OnError(tag.Item2, RazorResources.ParseError_TextTagCannotContainAttributes);
        }
        else
        {
          this.Accept(symbols);
          this.Span.EditHandler.AcceptedCharacters = AcceptedCharacters.None;
        }
        if (num == 0)
          tags.Push(tag);
        this.Output(SpanKind.Transition);
        return true;
      }
      this.Accept(this._bufferedOpenAngle);
      this.Optional(HtmlSymbolType.Text);
      return this.RestOfTag(tag, tags);
    }

    private bool RestOfTag(
      Tuple<HtmlSymbol, SourceLocation> tag,
      Stack<Tuple<HtmlSymbol, SourceLocation>> tags)
    {
      this.TagContent();
      if (this.At(HtmlSymbolType.OpenAngle))
        return false;
      bool flag1 = this.At(HtmlSymbolType.Solidus);
      if (flag1)
        this.AcceptAndMoveNext();
      bool flag2 = this.Optional(HtmlSymbolType.CloseAngle);
      if (!flag2)
        this.Context.OnError(tag.Item2, RazorResources.ParseError_UnfinishedTag, (object) tag.Item1.Content);
      else if (!flag1)
      {
        string str = tag.Item1.Content.Trim();
        if (this.VoidElements.Contains(str))
        {
          int absoluteIndex = this.CurrentLocation.AbsoluteIndex;
          IEnumerable<HtmlSymbol> symbols = this.ReadWhile(HtmlMarkupParser.IsSpacingToken(true));
          if (this.At(HtmlSymbolType.OpenAngle) && this.NextIs(HtmlSymbolType.Solidus))
          {
            HtmlSymbol currentSymbol1 = this.CurrentSymbol;
            this.NextToken();
            HtmlSymbol currentSymbol2 = this.CurrentSymbol;
            this.NextToken();
            if (this.At(HtmlSymbolType.Text) && string.Equals(this.CurrentSymbol.Content, str, StringComparison.OrdinalIgnoreCase))
            {
              this.Accept(symbols);
              this.Accept(currentSymbol1);
              this.Accept(currentSymbol2);
              this.AcceptAndMoveNext();
              this.AcceptUntil(HtmlSymbolType.CloseAngle, HtmlSymbolType.OpenAngle);
              return this.Optional(HtmlSymbolType.CloseAngle);
            }
          }
          this.Context.Source.Position = absoluteIndex;
          this.NextToken();
        }
        else if (string.Equals(str, "script", StringComparison.OrdinalIgnoreCase))
          this.SkipToEndScriptAndParseCode();
        else
          tags.Push(tag);
      }
      return flag2;
    }

    private void SkipToEndScriptAndParseCode()
    {
      bool flag = false;
      while (!flag && !this.EndOfFile)
      {
        this.SkipToAndParseCode(HtmlSymbolType.OpenAngle);
        SourceLocation currentLocation = this.CurrentLocation;
        this.AcceptAndMoveNext();
        this.AcceptWhile(HtmlSymbolType.WhiteSpace);
        if (this.Optional(HtmlSymbolType.Solidus))
        {
          this.AcceptWhile(HtmlSymbolType.WhiteSpace);
          if (this.At(HtmlSymbolType.Text) && string.Equals(this.CurrentSymbol.Content, "script", StringComparison.OrdinalIgnoreCase))
          {
            this.SkipToAndParseCode(HtmlSymbolType.CloseAngle);
            if (!this.Optional(HtmlSymbolType.CloseAngle))
              this.Context.OnError(currentLocation, RazorResources.ParseError_UnfinishedTag, (object) "script");
            flag = true;
          }
        }
      }
    }

    private bool AcceptUntilAll(params HtmlSymbolType[] endSequence)
    {
      while (!this.EndOfFile)
      {
        this.SkipToAndParseCode(endSequence[0]);
        if (this.AcceptAll(endSequence))
          return true;
      }
      this.Span.EditHandler.AcceptedCharacters = AcceptedCharacters.Any;
      return false;
    }

    private bool RemoveTag(
      Stack<Tuple<HtmlSymbol, SourceLocation>> tags,
      string tagName,
      SourceLocation tagStart)
    {
      Tuple<HtmlSymbol, SourceLocation> tuple = (Tuple<HtmlSymbol, SourceLocation>) null;
      while (tags.Count > 0)
      {
        tuple = tags.Pop();
        if (string.Equals(tagName, tuple.Item1.Content, StringComparison.OrdinalIgnoreCase))
          return true;
      }
      if (tuple != null)
        this.Context.OnError(tuple.Item2, RazorResources.ParseError_MissingEndTag, (object) tuple.Item1.Content);
      else
        this.Context.OnError(tagStart, RazorResources.ParseError_UnexpectedEndTag, (object) tagName);
      return false;
    }

    private void EndTagBlock(Stack<Tuple<HtmlSymbol, SourceLocation>> tags, bool complete)
    {
      if (tags.Count > 0)
      {
        while (tags.Count > 1)
          tags.Pop();
        Tuple<HtmlSymbol, SourceLocation> tuple = tags.Pop();
        this.Context.OnError(tuple.Item2, RazorResources.ParseError_MissingEndTag, (object) tuple.Item1.Content);
      }
      else if (complete)
        this.Span.EditHandler.AcceptedCharacters = AcceptedCharacters.None;
      tags.Clear();
      if (!this.Context.DesignTimeMode)
      {
        this.AcceptWhile(HtmlSymbolType.WhiteSpace);
        if (!this.EndOfFile && this.CurrentSymbol.Type == HtmlSymbolType.NewLine)
          this.AcceptAndMoveNext();
      }
      else if (this.Span.EditHandler.AcceptedCharacters == AcceptedCharacters.Any)
      {
        this.AcceptWhile(HtmlSymbolType.WhiteSpace);
        this.Optional(HtmlSymbolType.NewLine);
      }
      this.PutCurrentBack();
      if (!complete)
        this.AddMarkerSymbolIfNecessary();
      this.Output(SpanKind.Markup);
    }

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code. Parses the HTML document.</summary>
    public override void ParseDocument()
    {
      if (this.Context == null)
        throw new InvalidOperationException(RazorResources.Parser_Context_Not_Set);
      using (this.PushSpanConfig(new Action<SpanBuilder>(this.DefaultMarkupSpan)))
      {
        using (this.Context.StartBlock(BlockType.Markup))
        {
          this.NextToken();
          while (!this.EndOfFile)
          {
            this.SkipToAndParseCode(HtmlSymbolType.OpenAngle);
            this.ScanTagInDocumentContext();
          }
          this.AddMarkerSymbolIfNecessary();
          this.Output(SpanKind.Markup);
        }
      }
    }

    private bool ScanTagInDocumentContext()
    {
      if (this.Optional(HtmlSymbolType.OpenAngle))
      {
        if (this.At(HtmlSymbolType.Bang))
        {
          this.BangTag();
          return true;
        }
        if (this.At(HtmlSymbolType.QuestionMark))
        {
          this.XmlPI();
          return true;
        }
        if (!this.At(HtmlSymbolType.Solidus))
        {
          int num = !this.At(HtmlSymbolType.Text) ? 0 : (string.Equals(this.CurrentSymbol.Content, "script", StringComparison.OrdinalIgnoreCase) ? 1 : 0);
          this.Optional(HtmlSymbolType.Text);
          this.TagContent();
          this.Optional(HtmlSymbolType.Solidus);
          this.Optional(HtmlSymbolType.CloseAngle);
          if (num != 0)
            this.SkipToEndScriptAndParseCode();
          return true;
        }
      }
      return false;
    }

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code. Gets the HTML tags that are considered as void.</summary>
    /// <returns>The HTML tags that are considered as void.</returns>
    public ISet<string> VoidElements => this._voidElements;

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code. Gets the other parser for parsing HTML markup.</summary>
    /// <returns>The other parser for parsing HTML markup.</returns>
    protected override ParserBase OtherParser => this.Context.CodeParser;

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code. Gets the instance that defines the characteristics of HTML language.</summary>
    /// <returns>The instance that defines the characteristics of HTML language.</returns>
    protected override LanguageCharacteristics<HtmlTokenizer, HtmlSymbol, HtmlSymbolType> Language => (LanguageCharacteristics<HtmlTokenizer, HtmlSymbol, HtmlSymbolType>) HtmlLanguageCharacteristics.Instance;

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code. Builds the span for the given content using the specified span builder.</summary>
    /// <param name="span">The span builder used to build the span.</param>
    /// <param name="start">The start location.</param>
    /// <param name="content">The span content.</param>
    public override void BuildSpan(SpanBuilder span, SourceLocation start, string content)
    {
      span.Kind = SpanKind.Markup;
      span.CodeGenerator = (ISpanCodeGenerator) new MarkupCodeGenerator();
      base.BuildSpan(span, start, content);
    }

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code. Builds the span before the Razor comment.</summary>
    protected override void OutputSpanBeforeRazorComment() => this.Output(SpanKind.Markup);

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code. Skips the parse until the specified HTML symbol type is encountered.</summary>
    /// <param name="type">The HTML symbol type.</param>
    protected void SkipToAndParseCode(HtmlSymbolType type) => this.SkipToAndParseCode((Func<HtmlSymbol, bool>) (sym => sym.Type == type));

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code. Skips the parse until the specified condition is meet.</summary>
    /// <param name="condition">A function delegate that defines the condition.</param>
    protected void SkipToAndParseCode(Func<HtmlSymbol, bool> condition)
    {
      HtmlSymbol symbol = (HtmlSymbol) null;
      bool flag = false;
      while (!this.EndOfFile && !condition(this.CurrentSymbol))
      {
        if (this.At(HtmlSymbolType.NewLine))
        {
          if (symbol != null)
            this.Accept(symbol);
          flag = true;
          symbol = (HtmlSymbol) null;
          this.AcceptAndMoveNext();
        }
        else if (this.At(HtmlSymbolType.Transition))
        {
          HtmlSymbol currentSymbol = this.CurrentSymbol;
          this.NextToken();
          if (this.At(HtmlSymbolType.Transition))
          {
            if (symbol != null)
            {
              this.Accept(symbol);
              symbol = (HtmlSymbol) null;
            }
            this.Output(SpanKind.Markup);
            this.Accept(currentSymbol);
            this.Span.CodeGenerator = SpanCodeGenerator.Null;
            this.Output(SpanKind.Markup);
            this.AcceptAndMoveNext();
          }
          else
          {
            if (!this.EndOfFile)
              this.PutCurrentBack();
            this.PutBack(currentSymbol);
            if (symbol != null)
            {
              if (((this.Context.DesignTimeMode ? 0 : (symbol.Type == HtmlSymbolType.WhiteSpace ? 1 : 0)) & (flag ? 1 : 0)) != 0)
              {
                flag = false;
                this.PutBack(symbol);
                symbol = (HtmlSymbol) null;
              }
              else
              {
                this.Accept(symbol);
                symbol = (HtmlSymbol) null;
              }
            }
            this.OtherParserBlock();
          }
        }
        else if (this.At(HtmlSymbolType.RazorCommentTransition))
        {
          if (symbol != null)
          {
            this.Accept(symbol);
            symbol = (HtmlSymbol) null;
          }
          this.AddMarkerSymbolIfNecessary();
          this.Output(SpanKind.Markup);
          this.RazorComment();
        }
        else
        {
          flag &= this.At(HtmlSymbolType.WhiteSpace);
          if (symbol != null)
            this.Accept(symbol);
          symbol = this.CurrentSymbol;
          this.NextToken();
        }
      }
      if (symbol == null)
        return;
      this.Accept(symbol);
    }

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code. Returns the function delegate used to determine the token used for HTML spacing.</summary>
    /// <returns>The function delegate used to determine the token used for HTML spacing.</returns>
    /// <param name="includeNewLines">true to indicate that new lines are considered as spacing token; otherwise, false.</param>
    protected static Func<HtmlSymbol, bool> IsSpacingToken(bool includeNewLines) => (Func<HtmlSymbol, bool>) (sym =>
    {
      if (sym.Type == HtmlSymbolType.WhiteSpace)
        return true;
      return includeNewLines && sym.Type == HtmlSymbolType.NewLine;
    });

    private void OtherParserBlock()
    {
      this.AddMarkerSymbolIfNecessary();
      this.Output(SpanKind.Markup);
      using (this.PushSpanConfig())
      {
        this.Context.SwitchActiveParser();
        this.Context.CodeParser.ParseBlock();
        this.Context.SwitchActiveParser();
      }
      this.Initialize(this.Span);
      this.NextToken();
    }

    private bool CaseSensitive { get; set; }

    private StringComparison Comparison => !this.CaseSensitive ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;

    /// <summary>Parses a section with markups given by the nesting sequences.</summary>
    /// <param name="nestingSequences">A tuple that specifies the markup nesting sequences.</param>
    /// <param name="caseSensitive">true to indicate case-sensitive parsing; otherwise, false.</param>
    public override void ParseSection(Tuple<string, string> nestingSequences, bool caseSensitive)
    {
      if (this.Context == null)
        throw new InvalidOperationException(RazorResources.Parser_Context_Not_Set);
      using (this.PushSpanConfig(new Action<SpanBuilder>(this.DefaultMarkupSpan)))
      {
        using (this.Context.StartBlock(BlockType.Markup))
        {
          this.NextToken();
          this.CaseSensitive = caseSensitive;
          if (nestingSequences.Item1 == null)
            this.NonNestingSection(nestingSequences.Item2.Split());
          else
            this.NestingSection(nestingSequences);
          this.AddMarkerSymbolIfNecessary();
          this.Output(SpanKind.Markup);
        }
      }
    }

    private void NonNestingSection(string[] nestingSequenceComponents)
    {
      do
      {
        this.SkipToAndParseCode((Func<HtmlSymbol, bool>) (sym => sym.Type == HtmlSymbolType.OpenAngle || this.AtEnd(nestingSequenceComponents)));
        this.ScanTagInDocumentContext();
      }
      while ((this.EndOfFile || !this.AtEnd(nestingSequenceComponents)) && !this.EndOfFile);
      this.PutCurrentBack();
    }

    private void NestingSection(Tuple<string, string> nestingSequences)
    {
      int currentNesting = 1;
      while (currentNesting > 0 && !this.EndOfFile)
      {
        this.SkipToAndParseCode((Func<HtmlSymbol, bool>) (sym => sym.Type == HtmlSymbolType.Text || sym.Type == HtmlSymbolType.OpenAngle));
        if (this.At(HtmlSymbolType.Text))
        {
          currentNesting += this.ProcessTextToken(nestingSequences, currentNesting);
          if (this.CurrentSymbol != null)
            this.AcceptAndMoveNext();
          else if (currentNesting > 0)
            this.NextToken();
        }
        else
          this.ScanTagInDocumentContext();
      }
    }

    private bool AtEnd(string[] nestingSequenceComponents)
    {
      this.EnsureCurrent();
      if (!string.Equals(this.CurrentSymbol.Content, nestingSequenceComponents[0], this.Comparison))
        return false;
      int absoluteIndex = this.CurrentSymbol.Start.AbsoluteIndex;
      try
      {
        foreach (string sequenceComponent in nestingSequenceComponents)
        {
          if (!this.EndOfFile && !string.Equals(this.CurrentSymbol.Content, sequenceComponent, this.Comparison))
            return false;
          this.NextToken();
          while (!this.EndOfFile && HtmlMarkupParser.IsSpacingToken(true)(this.CurrentSymbol))
            this.NextToken();
        }
        return true;
      }
      finally
      {
        this.Context.Source.Position = absoluteIndex;
        this.NextToken();
      }
    }

    private int ProcessTextToken(Tuple<string, string> nestingSequences, int currentNesting)
    {
      for (int position = 0; position < this.CurrentSymbol.Content.Length; ++position)
      {
        int num = this.HandleNestingSequence(nestingSequences.Item1, position, currentNesting, 1);
        if (num == 0)
          num = this.HandleNestingSequence(nestingSequences.Item2, position, currentNesting, -1);
        if (num != 0)
          return num;
      }
      return 0;
    }

    private int HandleNestingSequence(
      string sequence,
      int position,
      int currentNesting,
      int retIfMatched)
    {
      if (sequence == null || (int) this.CurrentSymbol.Content[position] != (int) sequence[0] || (position + sequence.Length > this.CurrentSymbol.Content.Length || !string.Equals(this.CurrentSymbol.Content.Substring(position, sequence.Length), sequence, this.Comparison)))
        return 0;
      int position1 = this.Context.Source.Position;
      HtmlSymbol currentSymbol = this.CurrentSymbol;
      this.PutCurrentBack();
      Tuple<HtmlSymbol, HtmlSymbol> tuple1 = this.Language.SplitSymbol(currentSymbol, position, HtmlSymbolType.Text);
      HtmlSymbol symbol1 = tuple1.Item1;
      Tuple<HtmlSymbol, HtmlSymbol> tuple2 = this.Language.SplitSymbol(tuple1.Item2, sequence.Length, HtmlSymbolType.Text);
      HtmlSymbol symbol2 = tuple2.Item1;
      HtmlSymbol htmlSymbol = tuple2.Item2;
      if (!string.IsNullOrEmpty(symbol1.Content))
        this.Accept(symbol1);
      if (currentNesting + retIfMatched == 0)
      {
        this.Context.Source.Position = symbol2.Start.AbsoluteIndex;
      }
      else
      {
        this.Accept(symbol2);
        if (htmlSymbol != null)
          this.Context.Source.Position = htmlSymbol.Start.AbsoluteIndex;
        else
          this.Context.Source.Position = position1;
      }
      return retIfMatched;
    }
  }
}
